#ifndef __FILE_INFO_H__
#define __FILE_INFO_H__

#include "configure.h"
#include "yid.h"
#include "lsv.h"
#include "ec.h"
#include "../storage/controller/volume_proto_eclog.h"

#define MODE_MAX 01777

// ATTR
#define __FILE_ATTR_MULTPATH__          0x00000001
#define __FILE_ATTR_SNAPSHOT__          0x00000002
#define __FILE_ATTR_PROTECT__           0x00000004
#define __FILE_ATTR_CLONE__             0x00000008

#define __FILE_ATTR_LOCALIZE__          0x00000010
#define __FILE_ATTR_WRITEBACK__         0x00000020
#define __FILE_ATTR_DIRECT__            0x00000040
#define __FILE_ATTR_ECLOG__             0x00000080

#define __FILE_ATTR_DELETE__            0x00000100
#define __FILE_ATTR_PEEK__              0x00000200          //only peek, not read data to buf, no matter chunk is exists or not
#define __FILE_ATTR_NOFILL__            0x00000400          //if chunk not exists, no fill zero to buf, return ENOENT direct

// LSV
#define __FILE_ATTR_LSV__               0x00010000
#define __FILE_ATTR_INITED__            0x00020000
#define __FILE_ATTR_READRAW__           0x00040000
#define __FILE_ATTR_LSV_CLONE__         0x00080000

#define __FILE_ATTR_ROW2__              0x00100000
#define __FILE_ATTR_FLAT__              0x00200000
#define __FILE_ATTR_ROW3__              0x00400000

#pragma pack(8)

/*
 * 副本数之间关系：
 * / iscsi/ vol-->raw(repnum: parent.repnum_usr)
 * | |      |
 * | |      |--(repnum: repnum_sys)
 * | |      |--repnum_sys: LICH_REPLICA_METADATA
 * | |      `--repnum_usr: parent.repnum_usr --> usr_specify
 * | |
 * | |--(repnum: repnum_sys)
 * | |--repnum_sys: LICH_REPLICA_METADATA
 * | `--repnum_usr: parent.repnum_usr --> usr_specify
 * |
 * |--(repnum: repnum_sys)
 * |--repnum_sys: LICH_REPLICA_METADATA
 * `--repnum_usr: gloconf.chunk_rep --> usr_specify
 */
typedef struct {
        fileid_t id;
        uint16_t magic;
        uint8_t repnum_usr;        // 用户指定副本数
        uint8_t repnum_sys;        // 系统默认元数据副本数,默认为3副本，chkinfo中的repnum可能会分配不足
        uint64_t snap_rollback;     // 回滚目标快照的版本号
        uint64_t snap_version;      // 每个快照的版本号
        uint64_t reference;         // clone reference
        uint32_t attr;
        int32_t  priority;
        uint64_t snap_from;         // 在快照树上的父节点的版本号
        uint32_t __pad__[2];

        uint64_t size;             // physical volume size
        uint32_t mode;
        uint32_t uid;
        uint32_t gid;
        uint32_t ctime;
        uint32_t mtime;
        uint32_t btime;
        uint32_t atime;
#ifdef LSV
        uint64_t max_size;
        uint64_t logical_size;     // user-defined
        uint32_t volume_page_id;
        uint32_t gc_os_page_id;
        uint32_t gc_bitmap_page_id;
        uint32_t rcache_page_id;
        uint32_t wbuf_page_id;
        uint32_t bitmap_chunk_id;
        uint32_t system_power_off;
        // clone from volume's snap
        uint64_t source;
        char snap[128];
        // uint32_t lsv_attr;
#endif
        ec_t ec;
} fileinfo_t;

#pragma pack()

typedef struct {
        int metadata;
        int rollback;
        int chknum;
        int repnum;
        int sparse;
        int localized;
        uint64_t snap_rollback;
        uint64_t snap_version;
        uint64_t snap_from;
        uint64_t size;
#if LSV
        uint64_t logical_size;
        uint32_t volume_page_id;
        uint32_t gc_os_page_id;
        uint32_t gc_bitmap_page_id;
        uint32_t rcache_page_id;
        uint32_t wbuf_page_id;
        uint32_t bitmap_chunk_id;
        // clone
        uint64_t source;
        char snap[128];
#endif
        uint32_t attr;
        char src[MAX_NAME_LEN];
} filestat_t;

inline static uint64_t size2chknum(uint64_t size, const ec_t *ec)
{
        uint64_t chknum = 0;
        uint64_t chksize = 0;

        if (ec && EC_ISEC(ec))
                chksize = LICH_CHUNK_SPLIT * ec->k;
        else
                chksize = LICH_CHUNK_SPLIT;

        chknum = size / chksize;
        if (size % chksize)
                chknum++;

#if ECLOG_ENABLE
        if (ec && EC_ISEC(ec))
                chknum += _ceil(size, ECLOG_DATA_SIZE_ALIGN(ec)) * ECLOG_LOG_CHUNK_COUNT(ec);
#endif

        return chknum;
}

inline static uint64_t chknum2tabnum(uint32_t chknum)
{
        uint32_t tabnum = 0;

        tabnum = chknum / FILE_PROTO_EXTERN_ITEM_COUNT;
        if (chknum % FILE_PROTO_EXTERN_ITEM_COUNT)
                tabnum++;

        return tabnum;
}

static inline int fileattr_is_set(uint32_t attr, int flag)
{
        return (((attr & flag) ==  flag) ? 1 : 0);
}

static inline int is_volume_localize(const fileinfo_t *fileinfo)
{
        return fileattr_is_set(fileinfo->attr, __FILE_ATTR_LOCALIZE__);
        // return (((fileinfo->attr & __FILE_ATTR_LOCALIZE__) ==  __FILE_ATTR_LOCALIZE__) ? 1 : 0);
}

static inline int is_volume_clone(const fileinfo_t *fileinfo)
{
        return fileattr_is_set(fileinfo->attr, __FILE_ATTR_CLONE__);
}

static inline int is_lsv_inited(const fileinfo_t *fileinfo)
{
        return fileattr_is_set(fileinfo->attr, __FILE_ATTR_INITED__);
        // return (((fileinfo->attr & __FILE_ATTR_INITED__) ==  __FILE_ATTR_INITED__) ? 1 : 0);
}

#if LSV
static inline int is_lsv(const fileinfo_t *fileinfo)
{
        // return (((fileinfo->attr & __FILE_ATTR_LSV__) ==  __FILE_ATTR_LSV__) ? 1 : 0);
        return fileattr_is_set(fileinfo->attr, __FILE_ATTR_LSV__);
}

static inline int is_row2(const fileinfo_t *fileinfo)
{
        // return (((fileinfo->attr & __FILE_ATTR_LSV__) ==  __FILE_ATTR_LSV__) ? 1 : 0);
        return fileattr_is_set(fileinfo->attr, __FILE_ATTR_ROW2__);
}

static inline int is_row3(const fileinfo_t *fileinfo)
{
        // return (((fileinfo->attr & __FILE_ATTR_LSV__) ==  __FILE_ATTR_LSV__) ? 1 : 0);
        return fileattr_is_set(fileinfo->attr, __FILE_ATTR_ROW3__);
}

static inline volume_format_t lich_volume_format(const fileinfo_t *fileinfo) {
        if (is_row2(fileinfo)) {
                return VOLUME_FORMAT_ROW2;
        } else if (is_row3(fileinfo)) {
                return VOLUME_FORMAT_ROW3;
        } else if (is_lsv(fileinfo)) {
                return VOLUME_FORMAT_LSV;
        } else {
                return VOLUME_FORMAT_RAW;
        }
}

#else

static inline int is_lsv(const fileinfo_t *fileinfo)
{
        (void) fileinfo;
        return 0;
}

static inline int is_row2(const fileinfo_t *fileinfo)
{
        (void) fileinfo;
        return 0;
}

static inline volume_format_t lich_volume_format(const fileinfo_t *fileinfo)
{
        (void) fileinfo;
        return VOLUME_FORMAT_RAW;
}

#endif


static inline int is_rollback(const fileinfo_t *fileinfo) {
        return fileinfo->snap_version != fileinfo->snap_rollback;
}

#endif
